package com.piece.file.client.mongo;

import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.piece.core.framework.exception.ErrorCode;
import com.piece.core.framework.exception.FrameWorkException;
import com.piece.core.framework.util.file.FileUtil;
import com.piece.core.framework.util.object.BeanUtil;
import com.piece.core.framework.util.basic.SpringUtil;
import com.piece.core.framework.util.security.coder.MD5Coder;
import com.piece.file.client.AbstractFileClient;
import com.piece.file.model.TbSysFile;
import lombok.extern.slf4j.Slf4j;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import java.io.*;
import java.util.List;

/**
 * Mongo文件客户端
 */
@Slf4j
public class MongoFileClient extends AbstractFileClient<MongoFileClientConfig> {

    private GridFsTemplate gridFsTemplate;
    private GridFSBucket gridFSBucket;

    public MongoFileClient(String name, MongoFileClientConfig config) {
        super(name, config);
    }

    @Override
    protected void doInit() {
        if (!config.getBasePath().endsWith(File.separator)) {
            config.setBasePath(config.getBasePath() + File.separator);
        }

        this.gridFsTemplate = SpringUtil.getBean(GridFsTemplate.class);
        this.gridFSBucket = SpringUtil.getBean(GridFSBucket.class);
    }

    @Override
    public TbSysFile writeToServerStore(byte[] bytes, String path, String name, String md5, boolean stat) throws Exception {
        TbSysFile file = new TbSysFile();
        try {
            String storePathAndName = path + File.separator + name;
            file.setMd5(md5);

            List<TbSysFile> existFiles = tbSysFileService.findFileByMd5(md5);
            if (null != existFiles && existFiles.size() > 0) {
                file.setServerId(existFiles.get(0).getServerId());
                file.setServerPath(existFiles.get(0).getServerPath());
                file.setServerFileName(existFiles.get(0).getServerFileName());
                return file;
            }

            InputStream is = new ByteArrayInputStream(bytes);
            ObjectId objectId = gridFsTemplate.store(is, storePathAndName, FileUtil.getFileSuffix(storePathAndName));
            file.setServerId(objectId.toHexString());
            file.setServerPath(path);
            file.setServerFileName(name);
            return file;
        } catch (Exception e) {
            log.error("上传MongoFS文件异常：{}", e.getMessage());
            throw new FrameWorkException(ErrorCode.UPLOAD);
        }
    }

    @Override
    public InputStream downloadFile(TbSysFile file) throws Exception {
        String objectId = file.getServerId();
        try {
            Query query = Query.query(Criteria.where("_id").is(objectId));
            GridFSFile gridFSFile = gridFsTemplate.findOne(query);
            GridFsResource gridFsResource = new GridFsResource(gridFSFile, gridFSBucket.openDownloadStream(gridFSFile.getObjectId()));
            return gridFsResource.getInputStream();
        } catch (Exception e) {
            log.error("下载MongoFS文件异常：{}", e.getMessage());
            throw new FrameWorkException(ErrorCode.DOWNLOAD);
        }
    }

    @Override
    public void updateFile(TbSysFile file) {
        try {
            // 删除文件
            deleteServerFile(file);
            // 更新文件
            byte[] bytes = FileUtil.toByte(file.getFileInputStream());
            String md5 = MD5Coder.md5File(bytes);
            TbSysFile temp = writeToServerStore(bytes, file.getServerPath(), file.getServerFileName(), md5, false);
            BeanUtil.copyProperties(file, temp, "serverId", "serverPath", "serverFileName");
            updateTbSysFile(temp);
        } catch (Exception e) {
            log.error("MongoFS文件更新异常：{}", e.getMessage());
            throw new FrameWorkException(new ErrorCode(e.getMessage()));
        }
    }

    @Override
    public void deleteFile(TbSysFile file) throws Exception {
        deleteTbSysFile(file);
        deleteServerFile(file);
    }

    private void deleteServerFile(TbSysFile file) {
        if (checkMd5(file)) {
            return;
        }

        try {
            String storePath = file.getServerId();
            String objectId = storePath.substring(storePath.lastIndexOf("/") + 1);
            gridFSBucket.delete(new ObjectId(objectId));
        } catch (Exception e) {
            log.error("MongoFS文件删除异常：{}", e.getMessage());
            if (e.getMessage().indexOf("No file found") == -1) {
                throw new FrameWorkException(ErrorCode.DELETE);
            }
        }
    }
}
